#ifndef MEMORYPOOL_H
#define MEMORYPOOL_H

#include "common.h"

/**
 * MemoryPool is a pool that combines simple incremental pool
 * and Buddy Memory Allocation.
 * we can enjoy the low memory waste of incremental pool
 * and quick recycle/re-allocation of BMA at the same time
 */

/**
 * @brief The MemoryArea class
 */
#define MEM_AREA_FREE	1
#define MEM_AREA_MAGIC_N 19891031 //Used to check memory leak
class MemoryArea
{
    size_t sizeAndFree;
public:
    size_t magicNumber;
    size_t getSize() { return sizeAndFree & (~MEM_AREA_FREE); }
    void setSize(size_t size)
    {
        ASSERT_MSG(size!=0,"Cannot allocate size 0 for a MemoryArea");

        sizeAndFree = (sizeAndFree & MEM_AREA_FREE)|size;
    }

    void setFree(bool free)
    {
        sizeAndFree = (sizeAndFree & ~MEM_AREA_FREE)
            | free;
    }

    bool isFree()
    {
        return (sizeAndFree & MEM_AREA_FREE);
    }
};

class MemoryException
{
    char cStr[1024];
public:
    MemoryException( const char* pStr )
    {
        for( int i = 0; pStr[i] != '\0'; i++ )
        {
            cStr[i] = pStr[i];
        }
    }
    const char* what() { return &cStr[0]; }
    const char* toString() { return &cStr[0]; }
};

#include <vector>
#include <list>
using std::vector;
using std::list;

#define RECYCLE_MAX_INDEX 32 // Max 2^31 = 2Giga bytes
#define DEFAULT_BLOCK_SIZE  104857600 // Default 100m

class MemoryPool
{
    size_t BLOCK_SIZE; // Default block size
    vector< byte* > blocks;
    list< MemoryArea* > recycleList[RECYCLE_MAX_INDEX];
    byte* currentBlock;
    byte* currentPosition;
    size_t remainSizeInCurBlock;

#ifndef NDBG
    size_t requestSum;
    size_t allocSum;
    size_t recycleSize;
    size_t recycleAlloc;
#endif

public:
    MemoryPool( size_t blockSize = DEFAULT_BLOCK_SIZE );
    ~MemoryPool();
    void* allocate( size_t size );
    void addBlock( size_t size );
    void recycle( void* ptr );
    void destroy();
    void report();
};

#endif // MEMORYPOOL_H
